﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;



namespace DailyFx.UI
{

    public class LongRunningTaskManager : TaskScheduler
    {
		/// <summary>
		///		apartment state for threading .
		/// </summary>
        private readonly ApartmentState _state ;

		/// <summary>
		///		pooled threads .
		/// </summary>
        private readonly ConcurrentQueue<Thread> _threads ;

		/// <summary>
		///		all enlisted tasks .
		/// </summary>
        private readonly ConcurrentQueue<Task> _tasks ;

		/// <summary>
		///		the factory creating task(s) on ui thread .
		/// </summary>
		private readonly TaskFactory _factory;



		/// <summary>
		///		
		/// </summary>
        public LongRunningTaskManager ( ApartmentState state )
        {
            this._state = state;
            this._threads = new ConcurrentQueue<Thread>();
            this._tasks = new ConcurrentQueue<Task>();

			//
			this._factory = new TaskFactory ( this );
        }

		/// <summary>
		/// 
		/// </summary>
		public void RunTask ( Delegate action, object[] args )
		{
              this._factory.StartNew ( () => action.DynamicInvoke( args) );
			
		}

		/// <summary>
		/// 
		/// </summary>
        protected override void QueueTask ( Task task )
        {
            Thread thread = new Thread( () => this.TryExecuteTask(task) );

            thread.Name = "UI Thread";
            thread.SetApartmentState( this._state );
			thread.Start();
            
			this._threads.Enqueue( thread );
            this._tasks.Enqueue( task );
        }


		/**
		public override bool TryExecuteTask ( Task task )
		{
			return base.TryExecuteTask( task);
		}
		*/

		protected override bool TryExecuteTaskInline ( Task task, bool taskWasPreviouslyQueued )
        {
            Thread thread = new Thread(() => this.TryExecuteTask(task) );
			
			thread.Name = "UI Thread";
			thread.SetApartmentState(_state);
            thread.Start();
            
			this._threads.Enqueue(thread);
            this._tasks.Enqueue( task);

            return true;
        }

		/// <summary>
		/// 
		/// </summary>
        protected override IEnumerable<Task> GetScheduledTasks()
        {
            return this._tasks;
        }

       
    }

}
